#include <iostream>
#include <queue>
#include "SDL/SDL.h"
#include "SDL/SDL_net.h"
#include "SDL/SDL_thread.h"

#include "network.h"//socket server class
#include "csql.h"//MySql class

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>//To load files



using namespace std;


bool ShutDown;
cNetwork aNET;
csql aSQL;
std::string aquery;
std::vector<std::string> data;
std::vector<std::string> data2;

//existing vector
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

int Login( void *adata )//Master listener function/thread
{
cout << "Starting Login thread... " << endl;
std::string text;
bool doneLogin=false;
while(!doneLogin)//MAIN LOOP
    {
     // cout << "checking accounts queue" << endl;
     //  cout << "queue has " << aNET.LoginQueue.size() <<" messages" << endl;
if (aNET.LoginQueue.size()> 0)//queue has messages
    {
        text.clear();
        SDL_SemWait( aNET.ClientsLock );
        text = aNET.LoginQueue.front();//take a message out from the queue
        aNET.LoginQueue.pop();
        SDL_SemPost( aNET.ClientsLock );


        data.clear();
        split(text,'/',data);//I split it into strings
if (aNET.Clients[atoi(data[0].c_str())]->Connected)//Only if the client is connected
{
    Uint16 command = atoi(data[2].c_str());

        cout << "@" << command << "@ command.." << endl;
        //NOTE: data[0]=client UID, data[1]=command, data[2]=variable data
                std::string fullname;
                std::string username;
                std::string password;

        switch (command){
            case CREATE_NEW_ACCOUNT:
                cout << "New account request" << endl;
                data2.clear();
                split(data[3],'#',data2);//I split it into strings

                fullname = data2[0];
                username = data2[1];
                password = data2[2];

                cout << "Fullname " << fullname << endl;
                cout << "Username " << username << endl;
                cout << "Password " << password << endl;

                aquery.clear();
                aquery = "select * from accounts where email = '";
                aquery+= username;
                aquery += "'";
                cout << aquery << endl;
                aSQL.executequery(aquery.c_str());//executing select query
                if (aSQL.getrow())
                    {
                        //Username duplicate..
                        cout << "Duplicate username.." << endl;
                        aNET.Clients[atoi(data[0].c_str())]->SockSend(DUPLICATE_ACCOUNT,"");
                    }else{
                        //We have not found username, ok to insert..
                        cout << "We have not found username, ok to insert.." << endl;
                        aquery.clear();
                        aquery = "insert into accounts values (NULL,'";
                        aquery+= fullname;
                        aquery+="' , '";
                        aquery+= username;
                        aquery+="' , '";
                        aquery+= password;
                        aquery+="', NULL)";
                        cout << aquery << endl;
                        aSQL.executequery(aquery.c_str());//executing select query
                        cout << "New user inserted" << endl;
                        aNET.Clients[atoi(data[0].c_str())]->SockSend(NEW_ACCOUNT_ACCEPTED,"");
                        }
                    break;

            case LOGIN_WITH_ACCOUNT:
                cout << "Login request" << endl;
                data2.clear();
                split(data[3],'#',data2);//I split it into strings

                username = data2[0];
                password = data2[1];
                cout << "Username " << username << endl;
                cout << "Password " << password << endl;

                aquery.clear();
                aquery = "select * from accounts where email = '";
                aquery+= username;
                aquery += "'";
                cout << aquery << endl;
                aSQL.executequery(aquery.c_str());//executing select query
                if (aSQL.getrow())
                    {
                    //Username found
                    cout << aSQL.row[0] << " " << aSQL.row[1] << " " << aSQL.row[2] << " " << aSQL.row[3] << " " << aSQL.row[4] << endl;
                    std::string pass;
                    pass = aSQL.row[3];
                    if (pass.compare(password)==0)
                        {
                        cout << "Username/password match, login ok" << endl;
                        aNET.Clients[atoi(data[0].c_str())]->SockSend(ACCOUNT_ACCEPTED,"");
                        aNET.Clients[atoi(data[0].c_str())]->Login  = true;
                        }else{
                        //wrong password
                        cout << "Password mismatch.. " << endl;
                        aNET.Clients[atoi(data[0].c_str())]->SockSend(BAD_PASSWORD,"");
                        }
                    }else{
                    //We have not found username..
                    cout << "Username not found.." << endl;
                    aNET.Clients[atoi(data[0].c_str())]->SockSend(UNKNOW_USERNAME,"");
                    }
                break;
            }
        cout << text << endl;//print the string without dividing it
}//if connected

}//Loginqueue>0

SDL_Delay(5);
if (ShutDown==true)doneLogin =true;

}//while
cout << "Exiting Login thread..." << endl;
return 0;
}

//*********************************
//MAIN PROGRAM
//*********************************

int main()
{
ShutDown=false;

if(SDL_Init(0)==-1)//First I start SDL
    {
    cout << "SDL error: " << endl << SDL_GetError();//Starts SDL
    exit(1);//On SDL error, exit with return value 1
    }

//Second step, start the socket server

aNET.myserver = &aNET;
aNET.Start(100,55555); //start networking, up to 100 clients on port 55555

//3rd: start sql class and connect to MySql, database "rpgdata"

aSQL.connect("127.0.0.1","root", "rpgdata","rpgdata");

SDL_Thread *LoginThread;//The Master thread >> accepts new clients
int         LoginThreadReturn;//return value for master thread

LoginThread = NULL;
LoginThread = SDL_CreateThread( &Login, NULL );

  //       static int Master( void *data );//Master listener function/thread

std::string text,temp;
Uint16 UID;

cout << "/help -> Show that help" << endl;
cout << "/quit -> Exit program" << endl;


bool done=false;
std::string textin;

while(!done)
    {
     cout << "Enter Command" << endl;
     cin >> textin;
     if (textin.length()>4)
     {
          if (textin.compare(0,5,"/quit")==0)//Close server
          {
              cout << "/quit Command received" << endl;
              done = true;
              ShutDown=true;
              SDL_WaitThread(LoginThread,&LoginThreadReturn);
            }

        if (textin.compare(0,5,"/help")==0)//help
          {
            cout << "/help -> Show that help" << endl;
            cout << "/quit -> Exit program" << endl;
            }
    }else{
     // do nothing
    }
 }//while

cout << "SERVER QUITING..." << endl;

aNET.Finish();//finish socket server

cout << "All clients disconnected, server stoped.." <<endl;

    SDL_Quit();
    return 0;
}


